package com.exam.api.common;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import com.exam.api.common.exception.GlobalException;
import com.exam.api.common.web.ResultCode;
import lombok.extern.slf4j.Slf4j;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;

/**
 * 工具类
 *
 * @author bcheng
 */
@Slf4j
public class CommonUtil {

    /**
     * 获取时间类型
     *
     * @param dateType 时间类型
     * @return 时间范围
     */
    public static List<LocalDate> getDateType(String dateType) {
        if (StrUtil.isEmpty(dateType)) {
            return List.of();
        }
        LocalDate startDate;
        LocalDate endDate;
        LocalDate earlierStartDate;
        LocalDate earlierEndDate;
        if ("TO_DAY".equalsIgnoreCase(dateType)) {
            startDate = LocalDate.now();
            endDate = LocalDate.now();
            earlierStartDate = startDate.minusDays(1);
            earlierEndDate = endDate.minusDays(1);
        } else if ("TO_WEEK".equalsIgnoreCase(dateType)) {
            // 获取当前日期
            LocalDate today = LocalDate.now();
            // 获取本周第一天（周一）
            startDate = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));
            // 获取本周最后一天（周日）
            endDate = today.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
            earlierStartDate = startDate.minusWeeks(1);
            earlierEndDate = endDate.minusWeeks(1);
        } else if ("TO_MONTH".equalsIgnoreCase(dateType)) {
            // 获取当前日期
            LocalDate today = LocalDate.now();
            // 获取本月第一天
            startDate = today.with(TemporalAdjusters.firstDayOfMonth());
            // 获取本月最后一天
            endDate = today.with(TemporalAdjusters.lastDayOfMonth());
            earlierStartDate = startDate.minusMonths(1);
            earlierEndDate = endDate.minusMonths(1);
        } else if ("TO_YEAR".equalsIgnoreCase(dateType)) {
            // 获取当前日期
            LocalDate today = LocalDate.now();
            // 获取本年第一天
            startDate = today.with(TemporalAdjusters.firstDayOfYear());
            // 获取本年最后一天
            endDate = today.with(TemporalAdjusters.lastDayOfYear());
            earlierStartDate = startDate.minusYears(1);
            earlierEndDate = endDate.minusYears(1);
        } else {
            throw new GlobalException("时间类型错误");
        }
        return List.of(startDate, endDate, earlierStartDate, earlierEndDate);
    }


    /**
     * 所有CompletableFuture执行完成，超时则抛出异常
     * 最长等待时间为10分钟
     *
     * @param cfs CompletableFuture数组
     */
    public static void allOf10Minutes(CompletableFuture<?>... cfs) {
        allOf(10, TimeUnit.MINUTES, cfs);
    }

    /**
     * 所有CompletableFuture执行完成，超时则抛出异常
     *
     * @param timeout 超时时间
     * @param unit    时间单位
     * @param cfs     CompletableFuture数组
     */
    public static void allOf(long timeout, TimeUnit unit, CompletableFuture<?>... cfs) {
        allOf((e) -> {
            log.error(" <<<=== CompletableFuture 执行失败 ", e);
            @SuppressWarnings("unchecked")
            Throwable globalException = ExceptionUtil.getCausedBy(e, GlobalException.class);
            if (globalException == null) {
                throw new GlobalException(ResultCode.BUSY_NETWORK);
            }
            throw (GlobalException) globalException;
        }, timeout, unit, cfs);
    }

    /**
     * 所有CompletableFuture执行完成，超时则抛出异常
     *
     * @param throwable 抛出异常
     * @param timeout   超时时间
     * @param unit      时间单位
     * @param cfs       CompletableFuture数组
     */
    public static void allOf(Consumer<Throwable> throwable, long timeout, TimeUnit unit, CompletableFuture<?>... cfs) {
        try {
            CompletableFuture.allOf(cfs).get(timeout, unit);
        } catch (InterruptedException | ExecutionException | TimeoutException e) {
            throwable.accept(e);
        }
    }
}
